package figure8.GUI;

//Imports for the GUI classes.
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.lang.Math;
import java.text.DecimalFormat;

/**
 * JKnob.java - 
 *   Copied kindly from: 
 *   http://users.dickinson.edu/~braught/courses/cs132f00/classes/code/JKnob.src.html
 *   A knob component.  The knob can be rotated by dragging 
 *   a spot on the knob around in a circle.
 *   The knob will report its position in radians when asked.
 *
 * @author Grant William Braught
 * @author Dickinson College
 * @version 12/4/2000
 */

class JKnob 
extends JComponent
implements MouseListener, MouseMotionListener {

private static int radius = 30;
private static final int spotRadius = 5;

private double theta;
private Color knobColor;
private Color spotColor;

private boolean pressedOnSpot;
private double hi = Math.atan2(16,-18);
private double lo = Math.atan2(-16, -18);

/**
 * No-Arg constructor that initializes the position
 * of the knob to 0 radians (Up).
 */
public JKnob() {
this(0);
}

/**
 * Constructor that initializes the position
 * of the knob to the specified angle in radians.
 *
 * @param initAngle the initial angle of the knob.
 */
public JKnob(double initTheta) {
this(initTheta, Color.gray, Color.black);
}

/**
 * Constructor that initializes the position of the
 * knob to the specified position and also allows the
 * colors of the knob and spot to be specified.
 *
 * @param initAngle the initial angle of the knob.
 * @param initColor the color of the knob.
 * @param initSpotColor the color of the spot.
 */
public JKnob(double initPercent, Color initKnobColor, Color initSpotColor) {

	theta = (initPercent*(hi-lo))+lo;
	pressedOnSpot = false;
	knobColor = initKnobColor;
	spotColor = initSpotColor;

	this.addMouseListener(this);	
	this.addMouseMotionListener(this);
}

/**
 * Paint the JKnob on the graphics context given.  The knob
 * is a filled circle with a small filled circle offset 
 * within it to show the current angular position of the 
 * knob.
 *
 * @param g The graphics context on which to paint the knob.
 */
public void paint(Graphics g) {

// Draw the knob.
g.setColor(knobColor);
g.fillOval(0,0,2*radius,2*radius);

// Find the center of the spot.
Point pt = getSpotCenter();
int xc = (int)pt.getX();
int yc = (int)pt.getY();

// Draw the spot.
g.setColor(spotColor);
g.fillOval(xc-spotRadius+2, yc-spotRadius+2,
	   2*spotRadius-4, 2*spotRadius-4);
}

/**
 * Return the ideal size that the knob would like to be.
 *
 * @return the preferred size of the JKnob.
 */
public Dimension getPreferredSize() {
return new Dimension(2*radius,2*radius);
}

/**
 * Return the minimum size that the knob would like to be.
 * This is the same size as the preferred size so the
 * knob will be of a fixed size.
 *
 * @return the minimum size of the JKnob.
 */
public Dimension getMinimumSize() {
return new Dimension(2*radius,2*radius);
}

/**
 * Get the current anglular position of the knob.
 *
 * @return the current anglular position of the knob.
 */
public double getAngle() {
	return theta;
}

public double getPercent() {
	double result = ((getAngle()-lo)/(hi-lo));
	result = result > 0.98 ? 1 : result;
	result = result < 0.02 ? 0 : result;
	result = round2Dec(result);
	return result;
}

/** 
 * Calculate the x, y coordinates of the center of the spot.
 *
 * @return a Point containing the x,y position of the center
 *         of the spot.
 */ 
private Point getSpotCenter() {

// Calculate the center point of the spot RELATIVE to the
// center of the of the circle.

int r = radius - spotRadius;

int xcp = (int)(r * Math.sin(theta));
int ycp = (int)(r * Math.cos(theta));

// Adjust the center point of the spot so that it is offset
// from the center of the circle.  This is necessary becasue
// 0,0 is not actually the center of the circle, it is  the 
    // upper left corner of the component!
if(ycp <= -18){ 
	ycp = -18;
	if(xcp>0) xcp = 16;
	else xcp = -16;

}

int xc = radius + xcp; 
int yc = radius - ycp;

// Create a new Point to return since we can't  
// return 2 values!
return new Point(xc,yc);
}

/**
 * Determine if the mouse click was on the knob or
 * not.  If it was return true, otherwise return 
 * false.
 */
private boolean isOnSpot(Point pt) {
return (pt.distance(new Point(0,0)) <= (Math.sqrt(2*Math.pow(radius*2, 2))));
}

// Methods from the MouseListener interface.

public void mouseClicked(MouseEvent e) {}

public void mouseEntered(MouseEvent e) {}

public void mouseExited(MouseEvent e) {}

public void mousePressed(MouseEvent e) {
	Point mouseLoc = e.getPoint();
	pressedOnSpot = isOnSpot(mouseLoc);
}

public void mouseReleased(MouseEvent e) {
	pressedOnSpot = false;
}

public void mouseMoved(MouseEvent e) {}

public void mouseDragged(MouseEvent e) {
if (pressedOnSpot) {

    int mx = e.getX();
    int my = e.getY();

    
    // Compute the x, y position of the mouse RELATIVE
    // to the center of the knob.
    int mxp = mx - radius;
    int myp = radius - my;

    // Compute the new angle of the knob from the
    // new x and y position of the mouse.  
    // Math.atan2(...) computes the angle at which
    // x,y lies from the positive y axis with cw rotations
    // being positive and ccw being negative.

    if(myp >= -18)
    	theta = Math.atan2(mxp, myp);
    else
    	theta = Math.atan2(mxp, -18);
    repaint();
	try
	{
		Thread.sleep(75);
	}
	catch(InterruptedException err)
	{
		err.printStackTrace();
	}
}
}

public static void main(String[] args) {

JFrame myFrame = new JFrame("JKnob Test method");

Container thePane = myFrame.getContentPane();

// Add a JKnob to the pane.
thePane.add(new JKnob());

myFrame.addWindowListener(new WindowAdapter() {
         public void windowClosing(WindowEvent e) {
             System.exit(0);
         }
     });

myFrame.pack();
myFrame.show();
}

public double round2Dec(double d) {
	DecimalFormat twoDecForm = new DecimalFormat("#.##");
return Double.valueOf(twoDecForm.format(d));
}

}